#include "ithread.h"

#ifndef WIN32
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#endif


IThread::IThread()
{
	retval = NULL;
	mutexinit = false;
	running = false;
}

IThread::~IThread()
{
	Kill();
}

int IThread::Start()
{
	if (!mutexinit) {
		if (!runningmutex.IsInitialized()) {
			if (runningmutex.Init() < 0)
				return ERR_ITHREAD_CANTINITMUTEX;
		}
		if (!continuemutex.IsInitialized()) {
			if (continuemutex.Init() < 0)
				return ERR_ITHREAD_CANTINITMUTEX;
		}
		if (!continuemutex2.IsInitialized()) {
			if (continuemutex2.Init() < 0)
				return ERR_ITHREAD_CANTINITMUTEX;
		}
		mutexinit = true;
	}
	
	runningmutex.Lock();
	if (running) {
		runningmutex.Unlock();
		return ERR_ITHREAD_ALREADYRUNNING;
	}
	runningmutex.Unlock();

#ifdef WIN32	
	continuemutex.Lock();
	threadhandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)TheThread,this,0,(LPDWORD)&threadid);
	if (threadhandle == NULL) {
		continuemutex.Unlock();
		return ERR_ITHREAD_CANTSTARTTHREAD;
	}
#else
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CRATE_DETACHED);

	continuemutex.Lock();
	int statues = pthread_create(&threadid,&attr,TheThread,this);
	pthread_attr_destroy(&attr);
	if (status != 0) {
		continuemutex.Unlock();
		return ERR_ITHREAD_CANTSTARTTHREAD;
	}
#endif
	
	/* Wait until 'running' is set */
	runningmutex.Lock();			
	while (!running) {
		runningmutex.Unlock();
#ifdef WIN32
		Sleep(1);
#else
		struct timespec req, rem;
		req.tv_sec = 0;
		req.tv_nsec = 1000000;
		nanosleep(&req,&rem);
#endif
		runningmutex.Lock();
	}
	runningmutex.Unlock();
	continuemutex.Unlock();
	
	continuemutex2.Lock();
	continuemutex2.Unlock();
	return 0;
}

int IThread::Kill()
{
	runningmutex.Lock();			
	if (!running) {
		runningmutex.Unlock();
		return ERR_ITHREAD_NOTRUNNING;
	}

#ifdef WIN32
	TerminateThread(threadhandle,0);
	CloseHandle(threadhandle);
#else
	pthread_cancel(threadid);
#endif
	running = false;
	runningmutex.Unlock();
	return 0;
}

bool IThread::IsRunning()
{
	bool r;
	
	runningmutex.Lock();			
	r = running;
	runningmutex.Unlock();
	return r;
}

void *IThread::GetReturnValue()
{
	void *val;
	
	runningmutex.Lock();
	if (running)
		val = NULL;
	else
		val = retval;
	runningmutex.Unlock();
	return val;
}

#ifdef WIN32
UINT WINAPI IThread::TheThread(void *param)
#else
void *IThread::TheThread(void *param)
#endif
{
	IThread *ithread;
	void *ret;

	ithread = (IThread *)param;
	
	ithread->continuemutex2.Lock();
	ithread->runningmutex.Lock();
	ithread->running = true;
	ithread->runningmutex.Unlock();
	
	ithread->continuemutex.Lock();
	ithread->continuemutex.Unlock();
	
	ret = ithread->Thread();
	
	ithread->runningmutex.Lock();
	ithread->running = false;
	ithread->retval = ret;

#ifdef WIN32
	CloseHandle(ithread->threadhandle);
	ithread->runningmutex.Unlock();
	return 0;
#else
	ithread->runningmutex.Unlock();
	return NULL;		
#endif
}

void IThread::ThreadStarted()
{
	continuemutex2.Unlock();
}

